-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exit a language server if it sends a message with invalid json #9332
Exit a language server if it sends a message with invalid json #9332
Conversation
…ed from the lsp server
This is definitely a bug in the language server it should never be sending invalid json. I think this could be an ok change to be a bit more robust but I would add somekind of counter to abort after a give counter of invalid messages received (without any valid messages) to avoid keeping an obviously crashing/crashed/missebhaving program alive forever. What do you think @the-mikedavis |
I expected to see something in the JSONRPC spec about closing connections that send invalid JSON but it looks like we're only obligated to send an error response back when we receive a request with invalid JSON: https://www.jsonrpc.org/specification#error_object. (The message in the post is a notification though, so no response is necessary.) And the LSP spec doesn't say anything about invalid JSON. I think that closing the connection when we get non-JSON is reasonable though because JSONRPC says that we need to respond to all requests and if we can't parse a request enough to know that it's a request then we can't know that we have to respond to it. Pragmatically I think it would be ok to make this change but it invites some extra complexity as @pascalkuthe says: we want servers that are obviously malfunctioning to exit rather than hang around forever. So I think this should really be fixed in omnisharp rather than any changes in Helix. I would prefer that we fail fast in Helix rather than trying to accomodate broken language servers. |
I agree that it would be ideal to fix the root cause in omnisharp. I actually created an issue over there initially. We'll see what comes of that. I might take a stab at debugging from that side if I have time. There are some confusing aspects of the current helix behavior that made it harder to determine exactly what was going on. When the issue occurs, the LSP functionality just stops working from user's perspective. There's an error log for the json parse failure, but there are also a bunch of unrelated
At this point, omnisharp is still running. If I try to close helix, it hangs for a bit and writes an lsp shutdown timeout log like the one below. If I run
If helix is going to bail on an lsp server that it thinks is unhealthy, I think it should do so completely and let the lsp server close before spinning up the new one. At that point, running :lsp-restart could be used to re-launch the lsp if desired. As long as the error logs make it clear what's going on, I think that'd be preferable to what happens today. For now I think it probably makes sense to hold off on adding any additional complexity to account for straight up broken json coming from the lsp server. If you think all that seems reasonable, I can take a swing at making the change to how the error is handled and logged. |
Ah I see, in this case the client doesn't properly exit. Yeah let's properly shutdown the client in the Err case in helix/helix-lsp/src/transport.rs Lines 274 to 302 in eca3ccf
Improving the logging sounds good too: we can probably log that line at |
…and close the language server
…what's done in send
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
…-editor#9332) * Keep lsp event listener thread alive when malformed json is encountered from the lsp server * Update unexpected error flow in recv() to close outstanding requests and close the language server * Log malformed notifications as info instead of error * Make close_language_server a nested function inside recv, similar to what's done in send * Update malformed notification log text * Clean up new log text a bit * Initialize recv_buffer closer to where it's used * Use "exit" instead of "close" * Remove whitespace * Remove the need for a helper method to exit the language server * Match on Unhandled error explicitly and keep catch-all error case around
…-editor#9332) * Keep lsp event listener thread alive when malformed json is encountered from the lsp server * Update unexpected error flow in recv() to close outstanding requests and close the language server * Log malformed notifications as info instead of error * Make close_language_server a nested function inside recv, similar to what's done in send * Update malformed notification log text * Clean up new log text a bit * Initialize recv_buffer closer to where it's used * Use "exit" instead of "close" * Remove whitespace * Remove the need for a helper method to exit the language server * Match on Unhandled error explicitly and keep catch-all error case around
…-editor#9332) * Keep lsp event listener thread alive when malformed json is encountered from the lsp server * Update unexpected error flow in recv() to close outstanding requests and close the language server * Log malformed notifications as info instead of error * Make close_language_server a nested function inside recv, similar to what's done in send * Update malformed notification log text * Clean up new log text a bit * Initialize recv_buffer closer to where it's used * Use "exit" instead of "close" * Remove whitespace * Remove the need for a helper method to exit the language server * Match on Unhandled error explicitly and keep catch-all error case around
…-editor#9332) * Keep lsp event listener thread alive when malformed json is encountered from the lsp server * Update unexpected error flow in recv() to close outstanding requests and close the language server * Log malformed notifications as info instead of error * Make close_language_server a nested function inside recv, similar to what's done in send * Update malformed notification log text * Clean up new log text a bit * Initialize recv_buffer closer to where it's used * Use "exit" instead of "close" * Remove whitespace * Remove the need for a helper method to exit the language server * Match on Unhandled error explicitly and keep catch-all error case around
…-editor#9332) * Keep lsp event listener thread alive when malformed json is encountered from the lsp server * Update unexpected error flow in recv() to close outstanding requests and close the language server * Log malformed notifications as info instead of error * Make close_language_server a nested function inside recv, similar to what's done in send * Update malformed notification log text * Clean up new log text a bit * Initialize recv_buffer closer to where it's used * Use "exit" instead of "close" * Remove whitespace * Remove the need for a helper method to exit the language server * Match on Unhandled error explicitly and keep catch-all error case around
I've been struggling to get c# + omnisharp working reliably with helix. Omnisharp occasionally sends messages with malformed json, which causes the helix LSP event listener thread to die. After this happens, the LSP functionality within helix no longer works, even though omnisharp is still up and running. If I try to close helix at this point, it hangs for a bit and writes an lsp shutdown timeout log. If I run
:lsp-restart
, a second instance of omnisharp is started, leaving the first one running in the background.This PR updates the recv function in helix-lsp::transport to request that an LSP is exited after it sends a message that cannot be parsed. This causes the
Language server exited
message to be displayed in the status bar within the editor. Surprisingly, the omnisharp process is still running at this point. Despite that, exiting helix is quick and running:lsp-restart
restarts the process as expected.Additionally, I updated some logging that caused confusion as I was troubleshooting.